;;; comint-input-filter - function modes.
;;; comint-input-send - function
;;; comint-eol-on-send - boolean
+;;; comint-process-echoes - boolean
(defvar comint-prompt-regexp "^"
"Regexp to recognise prompts in the inferior process.
(defvar comint-input-ring-size 30
"Size of input history ring.")
+(defvar comint-process-echoes nil
+ "*If non-`nil', assume that the subprocess echoes any input.
+If so, delete one copy of the input so that only one copy eventually
+appears in the buffer.
+
+This variable is buffer-local.")
+
;;; Here are the per-interpreter hooks.
(defvar comint-get-old-input (function comint-get-old-input-default)
"Function that submits old text in comint mode.
(make-local-variable 'comint-eol-on-send)
(make-local-variable 'comint-ptyp)
(make-local-variable 'comint-exec-hook)
+ (make-local-variable 'comint-process-echoes)
(run-hooks 'comint-mode-hook)
(or comint-input-ring
(setq comint-input-ring (make-ring comint-input-ring-size))))
"Send input to process.
After the process output mark, sends all text from the process mark to
point as input to the process. Before the process output mark, calls value
-of variable comint-get-old-input to retrieve old input, copies it to the
-process mark, and sends it. A terminal newline is also inserted into the
-buffer and sent to the process. In either case, value of variable
-comint-input-sentinel is called on the input before sending it. The input
-is entered into the input history ring, if the value of variable
-comint-input-filter returns non-nil when called on the input.
-
-If variable comint-eol-on-send is non-nil, then point is moved to the end of
-line before sending the input.
-
-comint-get-old-input, comint-input-sentinel, and comint-input-filter are chosen
-according to the command interpreter running in the buffer. E.g.,
+of variable `comint-get-old-input' to retrieve old input, copies it to the
+process mark, and sends it. If variable `comint-process-echoes' is `nil',
+a terminal newline is also inserted into the buffer and sent to the process
+(if it is non-`nil', all text from the process mark to point is deleted,
+since it is assumed the remote process will re-echo it). The value of
+variable `comint-input-sentinel' is called on the input before sending it.
+The input is entered into the input history ring, if the value of variable
+`comint-input-filter' returns non-`nil' when called on the input.
+
+If variable `comint-eol-on-send' is non-`nil', then point is moved to the
+end of line before sending the input.
+
+`comint-get-old-input', `comint-input-sentinel', and `comint-input-filter'
+are chosen according to the command interpreter running in the buffer. E.g.,
If the interpreter is the csh,
comint-get-old-input is the default: take the current line, discard any
initial string matching regexp comint-prompt-regexp.
(goto-char pmark)
(insert copy)
copy))))
- (insert ?\n)
+ (if comint-process-echoes
+ (delete-region pmark (point))
+ (insert ?\n))
(if (funcall comint-input-filter input)
(ring-insert comint-input-ring input))
(funcall comint-input-sentinel input)
;;; rlogin.el --- remote login interface
+;; Author: Noah Friedman
;; Maintainer: Noah Friedman <friedman@prep.ai.mit.edu>
;; Keywords: unix, comm
(require 'comint)
+;;;###autoload
(defvar rlogin-program "rlogin"
"*Name of program to invoke rlogin")
+;;;###autoload
(defvar rlogin-explicit-args nil
"*List of arguments to pass to rlogin on the command line.")
+;;;###autoload
(defvar rlogin-mode-hook nil
"*Hooks to run after setting current buffer to rlogin-mode.")
-;; I think this is so obnoxious I refuse to enable it by default.
-;; In any case, there is a bug with regards to generating a quit while
-;; reading keyboard input in a process filter, so until that's fixed it's
-;; not safe to enable this anyway.
-(defvar rlogin-password-paranoia nil
- "*If non-`nil', query user for a password in the minibuffer when a
-Password: prompt appears. Stars will echo as characters are type.
+;;;###autoload
+(defvar rlogin-process-connection-type nil
+ "*If non-`nil', use a pty for the local rlogin process.
+If `nil', use a pipe (if pipes are supported on the local system).
-It's also possible to selectively enter passwords without echoing them in
-the minibuffer using the function `rlogin-password'.")
+Generally it is better not to waste ptys on systems which have a static
+number of them. On the other hand, some implementations of `rlogin' assume
+a pty is being used, and errors will result from using a pipe instead.")
-(defvar rlogin-last-input-line nil nil)
+;; Leave this nil because it makes rlogin-filter a tiny bit faster. Plus
+;; you can still call rlogin-password by hand.
+;;;###autoload
+(defvar rlogin-password-paranoia nil
+ "*If non-`nil', query user for a password in the minibuffer when a Password: prompt appears.
+It's also possible to selectively enter passwords without echoing them in
+the minibuffer using the command `rlogin-password' explicitly.")
;; Initialize rlogin mode map.
+;;;###autoload
(defvar rlogin-mode-map '())
(cond ((not rlogin-mode-map)
(setq rlogin-mode-map (full-copy-sparse-keymap comint-mode-map))
the rlogin when starting."
(interactive (list current-prefix-arg
(read-from-minibuffer "Open rlogin connection to host: ")))
- (let* ((buffer-name (format "*rlogin-%s*" host))
+ (let* ((process-connection-type rlogin-process-connection-type)
+ (buffer-name (format "*rlogin-%s*" host))
(args (if (and rlogin-explicit-args (listp rlogin-explicit-args))
(cons host rlogin-explicit-args)
(list host)))
(comint-mode)
(comint-exec (current-buffer) buffer-name rlogin-program nil args)
(setq proc (get-process buffer-name))
- (set-marker (process-mark proc) (point-min))
+ ;; Set process-mark to point-max in case there is text in the
+ ;; buffer from a previous exited process.
+ (set-marker (process-mark proc) (point-max))
(set-process-filter proc 'rlogin-filter)
(rlogin-mode)))))
(rlogin-explicit-args nil))
(unwind-protect
(progn
- (while (string-match "[ \t]*\\([^ \t]\\)+$" args)
+ (while (string-match "[ \t]*\\([^ \t]+\\)$" args)
(setq rlogin-explicit-args
(cons (substring args
(match-beginning 1)
(rlogin 1 host)))
;;;###autoload
-(defun rlogin-password ()
- "Play the paranoia game by not echoing entered password in buffer
-(stars will echo in the minibuffer instead."
+(defun rlogin-password (&optional proc)
+ "Read a password and send it to an rlogin session.
+For each character typed, a `*' is echoed in the minibuffer.
+End with RET, LFD, or ESC. DEL or C-h rubs out. C-u kills line.
+C-g aborts attempt to read and send password.
+
+Optional argument PROC is the process to which the password should be sent.
+If not provided, send to the process in the current buffer. This argument
+is intended primarily for use by `rlogin-filter'."
(interactive)
- (let ((input (comint-read-noecho "Enter password: " 'stars)))
- (insert-before-markers "\n")
- (comint-send-string (get-buffer-process (current-buffer))
- (format "%s\n" input))))
+ (or proc (setq proc (get-buffer-process (current-buffer))))
+ (let* ((buffer-name (buffer-name (process-buffer proc)))
+ (pass (comint-read-noecho (format "Password for buffer \"%s\": "
+ buffer-name)
+ 'stars)))
+ (and pass
+ (save-excursion
+ (set-buffer buffer-name)
+ (insert-before-markers "\n")
+ (comint-send-string proc (format "%s\n" pass))))))
;;;###autoload
(defun rlogin-mode ()
+ "Set major-mode for rlogin sessions.
+If `rlogin-mode-hook' is set, run it."
(interactive)
(kill-all-local-variables)
(comint-mode)
(use-local-map rlogin-mode-map)
(run-hooks 'rlogin-mode-hook))
+\f
(defun rlogin-filter (proc string)
- (let ((old-buffer (current-buffer))
- (old-match-data (match-data))
- at-max-pos
- moving)
- (unwind-protect
- (progn
- (set-buffer (process-buffer proc))
- (setq moving (= (point) (process-mark proc)))
- (save-excursion
- (goto-char (process-mark proc))
- (save-restriction
- (let ((beg (point)))
- (insert-before-markers string)
- (narrow-to-region beg (point))
- (goto-char (point-min))
- (while (search-forward "\C-m" nil t)
- (delete-char -1))
- (and rlogin-password-paranoia
- (setq string (buffer-substring (point-min) (point-max))))
- (goto-char (point-max))))
- (set-marker (process-mark proc) (point)))
- (and moving
- (goto-char (process-mark proc))))
- (set-buffer old-buffer)
- (store-match-data old-match-data)))
+ (save-excursion
+ (set-buffer (process-buffer proc))
+ (let ((proc-mark (process-mark proc))
+ (region-begin (point)))
+ (goto-char proc-mark)
+ (insert-before-markers string)
+ (goto-char region-begin)
+ (while (search-forward "\C-m" proc-mark t)
+ (delete-char -1))))
+ ;; Kludgy workaround for scroll-step bug in emacs. If point is at the
+ ;; top of the window, scroll step is nonzero, and you call
+ ;; insert-before-markers, the text is inserted off-screen. If
+ ;; scroll-step is 0, this doesn't happen.
+ (and (/= scroll-step 0)
+ (eq (process-buffer proc) (window-buffer (selected-window)))
+ (eq (point) (window-start))
+ (set-window-start (selected-window)
+ (save-excursion
+ (beginning-of-line)
+ (point))
+ 'noforce))
(and rlogin-password-paranoia
(string= "Password:" string)
- (let ((input (comint-read-noecho "Enter password: " 'stars)))
- (and input
- (progn
- (insert-before-markers "\n")
- (comint-send-string proc (format "%s\n" input)))))))
+ (rlogin-password proc)))
+;;;###autoload
(defun rlogin-send-Ctrl-C ()
(interactive)
(send-string nil "\C-c"))
+;;;###autoload
(defun rlogin-send-Ctrl-Z ()
(interactive)
(send-string nil "\C-z"))
+;;;###autoload
(defun rlogin-send-Ctrl-backslash ()
(interactive)
(send-string nil "\C-\\"))
+;;;###autoload
(defun rlogin-delchar-or-send-Ctrl-D (arg)
"Delete ARG characters forward, or send a C-d to process if at end of
buffer."